//************************************************** // for ATtiny402 Practice Keyer with Sleep + Buffer // // Pin1 Vcc Pin2 Dit Pin3 Dah Pin4 Led // Pin5 Piezo Pin7 Button Pin8 Gnd // XRQTechLab 2025.8.8 // Speed 10~30 WPM up by Button //************************************************** #include #include #include #define DIT_PIN 0 #define DAH_PIN 1 #define LED_PIN 2 #define PIEZO_PIN 3 #define BUTTON_PIN 4 int wpm = 10; int ditLength; int dahLength; bool ditPressed = false; bool dahPressed = false; bool squeezeMode = false; bool lastWasDit = false; volatile bool wakeUpFlag = false; unsigned long lastInputTime = 0; // バッファ機能追加 char paddleBuffer = 0; bool sending = false; void setup() { pinMode(DIT_PIN, INPUT_PULLUP); pinMode(DAH_PIN, INPUT_PULLUP); pinMode(LED_PIN, OUTPUT); pinMode(PIEZO_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(DIT_PIN), wakeISR, FALLING); attachInterrupt(digitalPinToInterrupt(DAH_PIN), wakeISR, FALLING); attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), wakeISR, FALLING); wpm = EEPROM.read(0); if (wpm < 10 || wpm > 30) { wpm = 10; } updateSpeed(); playOpeningMessage(); lastInputTime = millis(); } void loop() { if (millis() - lastInputTime > 60000) { goToSleep(); } if (digitalRead(BUTTON_PIN) == LOW) { delay(50); if (digitalRead(BUTTON_PIN) == LOW) { wpm++; if (wpm > 30) { wpm = 10; } EEPROM.write(0, wpm); updateSpeed(); playSpeedSignal(); lastInputTime = millis(); } } // 入力処理(送出中ならバッファに記録) if (!sending) { if (paddleBuffer) { if (paddleBuffer == '.') sendDit(); else if (paddleBuffer == '-') sendDah(); paddleBuffer = 0; } else { if (digitalRead(DIT_PIN) == LOW) { ditPressed = true; lastInputTime = millis(); } if (digitalRead(DAH_PIN) == LOW) { dahPressed = true; lastInputTime = millis(); } if (ditPressed && dahPressed) { squeezeMode = true; } if (squeezeMode) { sendSqueeze(); squeezeMode = false; } else { if (ditPressed) sendDit(); if (dahPressed) sendDah(); } } } else { // 送出中の入力を記録 if (digitalRead(DIT_PIN) == LOW) { paddleBuffer = '.'; } else if (digitalRead(DAH_PIN) == LOW) { paddleBuffer = '-'; } } } void goToSleep() { digitalWrite(LED_PIN, LOW); sleep_enable(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_cpu(); sleep_disable(); wakeUpFlag = false; lastInputTime = millis(); } void wakeISR() { wakeUpFlag = true; } void updateSpeed() { ditLength = 1200 / wpm; dahLength = ditLength * 3; } void sendDit() { sending = true; digitalWrite(LED_PIN, HIGH); tone(PIEZO_PIN, 800); delay(ditLength); digitalWrite(LED_PIN, LOW); noTone(PIEZO_PIN); delay(ditLength); ditPressed = false; lastWasDit = true; sending = false; } void sendDah() { sending = true; digitalWrite(LED_PIN, HIGH); tone(PIEZO_PIN, 800); delay(dahLength); digitalWrite(LED_PIN, LOW); noTone(PIEZO_PIN); delay(ditLength); dahPressed = false; lastWasDit = false; sending = false; } void sendSqueeze() { while (digitalRead(DIT_PIN) == LOW && digitalRead(DAH_PIN) == LOW) { if (lastWasDit) { sendDah(); } else { sendDit(); } } } void playSpeedSignal() { for (int i = 0; i < 3; i++) { tone(PIEZO_PIN, 800); delay(ditLength); noTone(PIEZO_PIN); delay(ditLength); } } void playOpeningMessage() { tone(PIEZO_PIN, 800); delay(ditLength); noTone(PIEZO_PIN); delay(ditLength); tone(PIEZO_PIN, 800); delay(dahLength); noTone(PIEZO_PIN); delay(ditLength); tone(PIEZO_PIN, 800); delay(ditLength); noTone(PIEZO_PIN); delay(ditLength); }